﻿namespace MicroCloud.AspNetCore.Mvc
{
    /// <summary>
    /// MVC模块基类
    /// </summary>
    [Description("MVC模块")]
    [DependsOnPacks(typeof(AspNetCorePack))]
    public abstract class MvcPackBase : AspPackBase
    {
        /// <summary>
        /// Cors跨源资源共享服务初始化器
        /// </summary>
        private ICorsInitializer _corsInitializer;

        #region 属性
        /// <summary>
        /// 获取 模块级别
        /// <para>级别越小越先启动</para>
        /// </summary>
        public override PackLevel Level => PackLevel.Framework;

        /// <summary>
        /// 获取 模块启动顺序编号
        /// <para>模块启动的顺序先按级别启动，级别内部再按此顺序启动，级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为 >0 的顺序值。</para>
        /// </summary>
        public override int OrderNo => 1;

        #endregion

        #region 方法
        /// <summary>
        /// 将模块服务添加到依赖注入服务容器中
        /// </summary>
        /// <param name="services">依赖注入服务容器</param>
        /// <returns></returns>
        public override IServiceCollection AddServices(IServiceCollection services)
        {
            _corsInitializer = services.GetOrAddSingleton(() => (ICorsInitializer)new DefaultCorsInitializer());
            services = _corsInitializer.AddCors(services);

            MicroCloudOptions MicroCloud = services.GetMicroCloudOptions();
            services.AddControllersWithViews()
                .AddControllersAsServices()
                .AddNewtonsoftJson(options =>
                {
                    //【默认:CamelCase：persionId 】【PascalCase：PersonId】【SnakeCase：person_id】【KebabCase：person-id】
                    if (MicroCloud.Mvc?.IsLowercaseJsonProperty == true)
                    {
                        //修改属性名称的序列化方式，首字母小写，即驼峰样式
                        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    }
                    else
                    {
                        //解决命名不一致问题 
                        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                    }

                    //循环引用处理
                    if (MicroCloud.Mvc?.ReferenceLoopHandling.IsMissing() == false)
                    {
                        var referenceLoopHandling = MicroCloud.Mvc?.ReferenceLoopHandling.ToLower();
                        switch (referenceLoopHandling)
                        {
                            case "error":
                                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Error;
                                break;
                            case "ignore":
                                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                                break;
                            case "serialize":
                                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
                                break;
                        }
                    }

                    //Null值处理
                    if (MicroCloud.Mvc?.NullValueHandling.IsMissing() == false)
                    {
                        var nullValueHandling = MicroCloud.Mvc?.NullValueHandling.ToLower();
                        switch (nullValueHandling)
                        {
                            case "include":
                                options.SerializerSettings.NullValueHandling = NullValueHandling.Include;
                                break;
                            case "ignore":
                                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                                break;
                        }
                    }

                    if (MicroCloud.Mvc?.StringEnumConvert == true)
                    {
                        //String与Enum类型转换器
                        options.SerializerSettings.Converters.Add(new StringEnumConverter());
                    }
                    if (MicroCloud.Mvc?.StringLongConvert == true)
                    {
                        //String与Long类型转换器，解决long类型在前端丢失精度的问题
                        options.SerializerSettings.Converters.Add(new StringLongConverter());
                    }

                    // 日期时间格式化处理 - 方式1
                    //options.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy/MM/dd HH:mm:ss" });
                    // 日期时间格式化处理 - 方式2
                    if (MicroCloud.Mvc?.DateFormatHandling.IsMissing() == false)
                    {
                        var dateFormatHandling = MicroCloud.Mvc?.DateFormatHandling.ToLower();
                        switch (dateFormatHandling)
                        {
                            case "iso":
                                options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
                                break;
                            case "microsoft":
                                options.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
                                break;
                        }
                    }
                    // 日期时间格式化字符串处理
                    if (MicroCloud.Mvc?.DateFormatString.IsMissing() == false)
                    {
                        var dateFormatString = MicroCloud.Mvc?.DateFormatString;
                        options.SerializerSettings.DateFormatString = dateFormatString;
                    }
                    // 日期时间时区处理
                    if (MicroCloud.Mvc?.DateTimeZoneHandling.IsMissing() == false)
                    {
                        var dateTimeZoneHandling = MicroCloud.Mvc?.DateTimeZoneHandling.ToLower();
                        switch (dateTimeZoneHandling)
                        {
                            case "local":
                                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                                break;
                            case "utc":
                                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                                break;
                            case "unspecified":
                                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified;
                                break;
                            case "roundtripkind":
                                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
                                break;
                        }

                    }
                    // 日期时间解析处理
                    if (MicroCloud.Mvc?.DateParseHandling.IsMissing() == false)
                    {
                        var dateParseHandling = MicroCloud.Mvc?.DateParseHandling.ToLower();
                        switch (dateParseHandling)
                        {
                            case "none":
                                options.SerializerSettings.DateParseHandling = DateParseHandling.None;
                                break;
                            case "datetime":
                                options.SerializerSettings.DateParseHandling = DateParseHandling.DateTime;
                                break;
                            case "datetimeoffset":
                                options.SerializerSettings.DateParseHandling = DateParseHandling.DateTimeOffset;
                                break;
                        }
                    }
                });

            services.AddControllers(options =>
            {
                // null值时，不返回204状态码。
                options.OutputFormatters.RemoveType(typeof(HttpNoContentOutputFormatter));
                options.OutputFormatters.Insert(0, new HttpNoContentOutputFormatter
                {
                    TreatNullValueAsNoContent = false,
                });
            });

            services.AddRouting(opts => opts.LowercaseUrls = MicroCloud.Mvc?.IsLowercaseUrls ?? false);

            services.AddHttpsRedirection(opts => opts.HttpsPort = 443);

            services.AddScoped<UnitOfWorkImpl>();
            services.AddTransient<UnitOfWorkAttribute>();
            services.TryAddSingleton<IVerifyCodeService, VerifyCodeService>();
            services.TryAddSingleton<IScopedServiceResolver, RequestScopedServiceResolver>();
            services.Replace<ICancellationTokenProvider, HttpContextCancellationTokenProvider>(ServiceLifetime.Singleton);
            services.Replace<IHybridServiceScopeFactory, HttpContextServiceScopeFactory>(ServiceLifetime.Singleton);

            services.AddHttpClient();

            return services;
        }

        /// <summary>
        /// 应用模块服务
        /// </summary>
        /// <param name="app">应用程序</param>
        public override void UsePack(WebApplication app)
        {
            _corsInitializer.UseCors(app);

            IsEnabled = true;
        }

        #endregion

    }

}
